﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using System.Windows.Media;
using System.Windows.Media.Animation;

using SBPweb.RIA.Client.Contracts.Base;
using SBPweb.RIA.Client.Controls.Base;

namespace SBPweb.RIA.Client.Controls.Extensions
{
    
    public static class UIElementExtentions
    {

        #region Animation

        public static void AnimateDoubleTo(this UIElement element, int miliseconds, object propertyPath, double value, EventHandler completed)
        {
            AnimateDoubleTo(element, miliseconds, propertyPath, value, null, completed);
        }

        public static void AnimateDoubleTo(this UIElement element, int miliseconds, object propertyPath, double value, IEasingFunction easing, EventHandler completed)
        {
            // Create a new storyboard
            var sb = new Storyboard();
            // Create a double animation
            var da = new DoubleAnimation();
            da.Duration = new TimeSpan(0, 0, 0, 0, miliseconds);
            // Set target property and target
            Storyboard.SetTargetProperty(da, new PropertyPath(propertyPath));
            Storyboard.SetTarget(da, element);
            if (easing != null)
            {
                da.EasingFunction = easing;
            }
            da.To = value;
            // Add the doubleanimation to the storyboard
            sb.Children.Add(da);
            
            // Add the storyboard to the Rootvisual of the application
            ((FrameworkElement)Application.Current.RootVisual).Resources.Add(Guid.NewGuid().ToString(), sb);

            // Begin the animation
            sb.Begin();

            if (completed != null)
            {
                sb.Completed += completed;
            }
        }

        public static void AnimateColorTo(this UIElement element, int miliseconds, object propertyPath, Color color, EventHandler completed)
        {
            AnimateColorTo(element, miliseconds, propertyPath, color, null, completed);
        }

        public static void AnimateColorTo(this UIElement element, int miliseconds, object propertyPath, Color color, IEasingFunction easing, EventHandler completed)
        {
            // Create a new storyboard
            var sb = new Storyboard();
            // Create a double animation
            var da = new ColorAnimation();
            da.Duration = new TimeSpan(0, 0, 0, 0, miliseconds);
            // Set target property and target
            Storyboard.SetTargetProperty(da, new PropertyPath(propertyPath));
            Storyboard.SetTarget(da, element);
            if (easing != null)
            {
                da.EasingFunction = easing;
            }
            da.To = color;
            // Add the doubleanimation to the storyboard
            sb.Children.Add(da);

            // Add the storyboard to the Rootvisual of the application
            ((FrameworkElement)Application.Current.RootVisual).Resources.Add(Guid.NewGuid().ToString(), sb);

            // Begin the animation
            sb.Begin();

            if (completed != null)
            {
                sb.Completed += completed;
            }
        }

        public static Storyboard GetStory(this Control sender, FrameworkElement element, string storyName)
        {
            string dis = string.Empty;
            if (!sender.IsEnabled)
            {
                dis = "Disabled";
            }
            Storyboard sb = element.FindName(storyName + dis) as Storyboard;
            if (sb == null)
            {
                sb = element.Resources[storyName + dis] as Storyboard;
            }
            //foreach (Timeline tl in sb.Children)
            //{
            //    Storyboard.SetTarget(tl, element);
            //}
            return sb;
        }

        public static Storyboard StartStory(this Control sender, FrameworkElement element, string storyName)
        {
            Storyboard sb = GetStory(sender, element, storyName);
            if (sb == null)
            {
                return null;
            }
            sb.Begin();
            return sb;
        }

        #endregion

        #region Element search

        public static T FindChildElement<T>(this UIElement element, string name)
            where T : FrameworkElement
        {
            return FindChildElement<T>(element, ExtendableApplication.Current.RootVisual, name);
        }

        public static T FindChildElement<T>(this UIElement element, UIElement parent, string name)
            where T : FrameworkElement
        {
            List<FrameworkElement> elements = new List<FrameworkElement>();
            FindDownInTree(elements, parent, typeof(T), name);
            if (elements.Count == 0)
            {
                return default(T);
            }
            return (T)elements[0];
        }


        public static T FintParentElement<T>(this FrameworkElement element, string parentName)
            where T : FrameworkElement
        {
            return FindUpInTree<T>(element, parentName);
        }

        public static bool HasParent(this UIElement element, DependencyObject parent)
        {
            return HasParent<DependencyObject>(element, parent);
        }

        public static bool HasParent<TParent>(this UIElement element, TParent parent)
            where TParent : DependencyObject
        {
            return FindUpInTree(element, parent);
        }

        public static bool HasParent(this FrameworkElement element, string parentName)
        {
            return HasParent<FrameworkElement>(element, parentName);
        }

        public static bool HasParent<TParent>(this FrameworkElement element, string parentName)
            where TParent : FrameworkElement
        {
            TParent ret = FindUpInTree<TParent>(element, parentName);
            return ret != default(TParent);
        }

        private static void FindDownInTree(List<FrameworkElement> elements, DependencyObject parent, Type controlType, string name)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
            {
                FrameworkElement visual = VisualTreeHelper.GetChild(parent, i) as FrameworkElement;
                if (controlType.IsInstanceOfType(visual) && visual.Name == name)
                {
                    elements.Add(visual);
                }
                if (visual != null)
                {
                    FindDownInTree(elements, visual, controlType, name);
                }
            }
        }

        private static bool FindUpInTree(DependencyObject element, DependencyObject parent)
        {
            if (element == null)
            {
                return false;
            }
            if (element == parent)
            {
                return true;
            }
            return FindUpInTree(VisualTreeHelper.GetParent(element), parent);
        }
        
        private static T FindUpInTree<T>(FrameworkElement element, string parentName)
            where T : FrameworkElement
        {
            if (element == null)
            {
                return null;
            }
            if (element.Name == parentName)
            {
                Type t = typeof(T);
                if (t.IsAssignableFrom(element.GetType()))
                {
                    return (T)element;
                }
                return default(T);
            }
            return FindUpInTree<T>(VisualTreeHelper.GetParent(element) as FrameworkElement, parentName);
        }

        #endregion

    }

}